---
sidebar_position: 6
title: Cache
sidebar_label: Cache
---

[Read the API Reference »](/docs/api/core/Classes/Cache.mdx)

The `Cache` class is a core subsystem in Hyper Fetch, responsible for storing and managing response data from requests.
It provides a flexible, event-driven system for data retention, validation, and propagation throughout your application.
By default, it uses an in-memory `Map` for storage, but you can easily swap in persistent storage solutions like
`localStorage` or `IndexedDB`.

---

:::tip Purpose

1. **Store and manage request results** for fast, reliable data access.
2. **Emit events** to keep your app in sync with cache changes.
3. **Support flexible storage**—from in-memory to persistent solutions.
4. **Integrate seamlessly** with the Client and Request systems for a unified data flow.

:::

---

## Quick Start

Here's how to get started with the Cache in Hyper Fetch:

```tsx title="Basic Cache Usage"
import { createClient, Cache } from "@hyper-fetch/core";

// Initialize the client with default cache
const client = createClient({ url: "http://localhost:3000" });

// Read from cache
const data = client.cache.get("key");

// Write to cache
client.cache.set("key", { data: "value" });
```

You can also customize the cache storage:

```tsx title="Custom Cache Storage"
const client = createClient({
  url: "http://localhost:3000",
  cache: (instance) => new Cache(instance, { storage: localStorage }),
});
```

<LinkCard
  type="docs"
  title="Client"
  description="Learn how to configure the Client and its subsystems."
  to="/docs/core/client"
/>

<LinkCard
  type="docs"
  title="Request"
  description="Understand how requests interact with the cache."
  to="/docs/core/request"
/>

---

## Available methods

<ShowMore>

(@import core Cache type=methods&display=table)

</ShowMore>

<LinkCard
  type="api"
  title="Detailed Cache API Methods"
  description="Explore all available methods, their parameters, and return values for the Cache class."
  to="/docs/api/core/Classes/Cache#methods"
/>

---

## Features

- **Key-based storage**: Data is stored and retrieved using unique cache keys, auto-generated from request details.
- **Flexible storage**: Use in-memory, localStorage, IndexedDB, or any compatible storage interface.
- **Event-driven**: Emits events on cache changes for real-time updates.
- **Persistence**: Easily enable persistent cache across sessions.
- **Fine-grained control**: Read, write, update, delete, and invalidate cache entries with simple methods.
- **Integration**: Works seamlessly with the Client and Request systems.

---

## How it works

The cache stores data on a **key-value** basis. The key (usually `cacheKey`) is auto-generated from the request's
method, endpoint, and query params, but you can override it for advanced scenarios.

```tsx
const getUsers = client.createRequest()({
  method: "GET",
  endpoint: "/users",
});

// get data by cache key
// highlight-start
const data = client.cache.get(getUsers.cacheKey);
// highlight-end

// or directly by request instance
// highlight-start
const data = getUsers.read();
// highlight-end
```

You can also set a custom cache key:

```tsx
const getUsers = client.createRequest()({
  method: "GET",
  endpoint: "/users",
  cacheKey: "CUSTOM_CACHE_KEY",
});

// get data by custom cache key
// highlight-start
const data = client.cache.get("CUSTOM_CACHE_KEY");
// highlight-end

// or directly by request instance
// highlight-start
const data = getUsers.read();
// highlight-end
```

---

## CacheKey

The `cacheKey` is a unique identifier for the cache entry. By default it is auto-generated from the request's endpoint,
url params and query params but you can still add the key manually when setting the Request or generic generator.

```tsx
const getUser = client.createRequest()({
  method: "GET",
  endpoint: "/users/:userId",
});

// highlight-start
const cacheKey = getUser.cacheKey; // "/users/:userId"
const cacheKeyWithParams = getUser.setParams({ userId: 1 }).cacheKey; // "/users/1"
const cacheKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).cacheKey; // "/users/:userId?page=1"
// highlight-end
```

### Custom cacheKey

You can also set a custom cache key:

```tsx
import { client } from "./api";

const getUser = client.createRequest()({
  method: "GET",
  endpoint: "/users/:userId",
  cacheKey: "CUSTOM_CACHE_KEY",
});

// highlight-start
console.log(getUser.cacheKey); // "CUSTOM_CACHE_KEY"
// highlight-end
```

### Generic cacheKey

You can also set a generic cache key:

```tsx
import { client } from "./api";

// highlight-start
client.setCacheKeyMapper((request) => {
  if (request.requestOptions.endpoint === "/users/:userId") {
    return `CUSTOM_CACHE_KEY_${request.params?.userId || "unknown"}`;
  }
});
// highlight-end

const getUser = client.createRequest()({
  method: "GET",
  endpoint: "/users/:userId",
});

// highlight-start
console.log(getUser.setParams({ userId: 1 }).cacheKey); // "CUSTOM_CACHE_KEY_1"
// highlight-end
```

---

## Quick Start

1. ### Reading from Cache

Use the `get` method to read data stored under a given key:

```tsx
const data = client.cache.get("key");
```

Or with a request instance:

```tsx
const getNote = client.createRequest<{ response: Note }>()({
  method: "GET",
  endpoint: "/notes/:noteId",
});

// highlight-start
const data = getNote.setParams({ noteId: 1 }).read();
console.log(data); // Note or undefined
// highlight-end
```

---

2. ### Writing to Cache

Use the `set` method to store data under a given key. Pass the request instance to ensure correct configuration:

```tsx
const getNote = client.createRequest()({
  method: "GET",
  endpoint: "/notes/:noteId",
});

client.cache.set(getNote.setParams({ noteId: 1 }), {
  data: { text: "Hello World" },
  error: null,
  status: 200,
  success: true,
  extra: xhrExtra,
});
```

---

3. ### Updating Cache

Update existing cache entries with the `update` method. The cache will **not** update if the initial data is missing.

:::info Updating rules

Cache will **NOT** update if the initial data is not present in the cache.

:::

```tsx
client.cache.update(getNote.setParams({ noteId: 1 }), {
  data: { text: "Hello World" },
  error: null,
  status: 200,
  success: true,
  extra: xhrExtra,
});

// Or with a callback
client.cache.update(getNote.setParams({ noteId: 1 }), (prevData) => ({
  ...prevData,
  data: { text: "Hello World" },
}));
```

---

4. ### Deleting from Cache

Remove data from the cache using the `delete` method:

```tsx
client.cache.delete(getNote.setParams({ noteId: 1 }).cacheKey);
// OR
client.cache.delete("CUSTOM_CACHE_KEY");
```

---

5. ### Invalidating Cache

Invalidate cache entries with the `invalidate` method. This sets the `staleTime` to 0, so the next request will refetch
the data. It also emits an event, triggering refetching in dedicated frameworks integrations like for example in React.

```tsx
client.cache.invalidate(getNote.setParams({ noteId: 1 }).cacheKey);
// OR
client.cache.invalidate("CUSTOM_CACHE_KEY");
// OR via RegExp
client.cache.invalidate(new RegExp("CUSTOM_CACHE_KEY"));
```

---

## Persistence

Enable persistent cache by providing a compatible storage interface (e.g., localStorage, IndexedDB):

```tsx
const client = createClient({
  url: "http://localhost:3000",
  cache: (instance) => new Cache(instance, { storage: localStorage }),
});
```

<LinkCard
  type="guides"
  title="Persistence"
  description="Learn how to enable persistent cache."
  to="/docs/guides/core/advanced/persistence"
/>

:::info

Currently, there is no cross-tab synchronization. This is planned for a future release.

:::

---

## Events & Lifecycle

The cache emits events on changes, allowing you to react to updates in real time. See all available events:

<ShowMore>

(@import core getCacheEvents type=returns)

</ShowMore>

<LinkCard
  type="api"
  title="Cache Events API"
  description="Learn more about cache events."
  to="/docs/api/core/Functions/getCacheEvents"
/>

---

## Configuration Options

You can configure the cache with various options:

(@import core CacheOptionsType type=returns)

<LinkCard
  type="guides"
  title="Lazy storage"
  description="Learn more about lazy storages."
  to="/docs/guides/core/advanced/persistence#async-persistence-storages"
/>

---

## TypeScript

The Cache system is fully typed and integrates with your Client and Request types. When using TypeScript, you get full
type safety for cache operations, including data, error, and extra fields.

```tsx
const getUser = client.createRequest<{ response: { name: string } }>()({ endpoint: "/users/:id" });

// highlight-start
const data = getUser.setParams({ id: 1 }).read();
console.log(data); // { name: string }
// highlight-end
```

---

## See Also

<LinkCard
  type="docs"
  title="Client"
  description="Central configuration and entry point for all requests."
  to="/docs/core/client"
/>

<LinkCard
  type="docs"
  title="Request"
  description="How requests interact with the cache and other subsystems."
  to="/docs/core/request"
/>
